package top.yangbuyi.system.realm;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import top.yangbuyi.system.common.ActiveUser;
import top.yangbuyi.system.common.Constant;
import top.yangbuyi.system.common.WebUtils;
import top.yangbuyi.system.domain.User;
import top.yangbuyi.system.service.MenuService;
import top.yangbuyi.system.service.RoleService;
import top.yangbuyi.system.service.UserService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
import java.util.Set;

/**
 * ClassName: UserRealm
 * Description: 杨不易网站 :www.yangbuyi.top
 * date: 2020/4/14 20:30
 *
 * @author TeouBle
 * @author yangbuyi
 * @since JDK 1.8
 */
public class UserRealm extends AuthorizingRealm {
      /**
       * @Lazy 让代理先走  要不然 切面失效  缓存
       */
      
      @Autowired
      @Lazy
      private UserService userService;
      
      
      @Autowired
      @Lazy
      private RoleService roleService;
      
      @Autowired
      @Lazy
      private MenuService menuService;
      
      
      @Override
      public String getName() {
            return this.getClass().getSimpleName();
      }
      
      /**
       * 认证
       *
       * @param authenticationToken
       * @throws AuthenticationException
       * @return AuthenticationInfo
       */
      @Override
      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            // 获取认证信息
            String userName = authenticationToken.getPrincipal().toString();
            // 判断该信息是否存在
            User user = userService.queryUserByLoginName(userName);
            try {
                  if (null != user) {
                        // 储存起来
                        ActiveUser activeUser = new ActiveUser();
                        activeUser.setUser(user);
                        // 根据用户ID  查询角色名称的集合
                        List<String> roles = this.roleService.queryRoleNamesByUid(user.getId());
                        // 根据用户ID  查询权限编码的集合
                        List<String> permissions = this.menuService.queryPermissionCodesByUserId(user.getId());
                        activeUser.setRoles(roles);
                        activeUser.setPermissions(permissions);
                        /* 设置当前用户 给到共享线程 */
                        WebUtils.setThisName(user);
                        if (user.getAvailable() != 1) {
                              throw new LockedAccountException("账户已被锁定");
                        }
                       
                       // 单用户登陆 失败
                       // this.singleUseLogin(userName);
                        // 进行认证
                        return new SimpleAuthenticationInfo(activeUser, user.getPwd(), ByteSource.Util.bytes(user.getSalt()), getName());
                  }
            } catch (UnknownAccountException u) {
                  throw new UnknownAccountException("用户不存在！");
            }
            return null;
      }
      
      @Autowired
      private StringRedisTemplate redisTemplate;
      
      /**
       * @param loginName
       * @功能描述： 单用户登录, 清除当前用户以前登录时保存的session会话
       */
      public void singleUseLogin(String loginName) {
            // 1.获取当前用户sessionId
            String currentUserSessionId = SecurityUtils.getSubject().getSession().getId().toString();
            // 2.获取shiro的sessionManager
            DefaultWebSecurityManager securityManager = (DefaultWebSecurityManager) SecurityUtils.getSecurityManager();
            // 拿到shiro  session
            DefaultWebSessionManager sessionManager = (DefaultWebSessionManager) securityManager.getSessionManager();
            // 3.获取所有已登录用户的session列表"shiro:session:" +
            Set<String> keys = redisTemplate.keys("*");
            // Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();
            
            Subject subject = SecurityUtils.getSubject();
            ActiveUser active = (ActiveUser) subject.getPrincipal();
            System.out.println(active);
            if (keys != null) {
                  if (keys.size() > 1) {
                        System.out.println("仅允许单用户登录,开始清理遗留用户信息~");
                        
                        if (active != null) {
                              for (String onlineSession : keys) {
                                    
                                    if (currentUserSessionId.contains(active.getUser().getLoginname())) {
                                          System.out.println(currentUserSessionId + ":" + onlineSession);
                                          // 清楚session
                                          HttpServletRequest httpServletRequest = WebUtils.getHttpServletRequest();
                                          HttpSession session = httpServletRequest.getSession();
                                          session.invalidate();
                                          // 退出认证
                                          subject.logout();
                                          // 清理缓存
                                          String header = org.apache.shiro.web.util.WebUtils.toHttp(httpServletRequest).getHeader("TOKEN");
                                          System.out.println("token:" + header);
                                          // 删除redis缓存当中的  token
                                          redisTemplate.delete(header);
                                    }
                                    
                                    // d575b3c5-645e-4543-b6e1-b02dd96dcdca

//                              System.out.println(onlineSession);
//                              // 4. 清除当前用户以前登录时保存的session会话
//                             // String valueOf = String.valueOf(onlineSession.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
//                              // 如果是同一个用户，但是不是同一个session，则剔除该用户以前的登录会话
//                              if (loginName.equals(onlineSession) && !onlineSession.equals(currentUserSessionId)) {
//                                    sessionManager.getSessionDAO().delete(onlineSession);
//                                    System.out.println("清理用户[" + loginName + "],SessionId为[" + onlineSession.getId() + "]的Session信息!");
//                              }
                                    
                                    System.out.println(currentUserSessionId + "------:" + onlineSession);
                                    
                              }
                        }
                        
                  } else {
                        System.out.println("无可清理用户信息~");
                  }
            }
            
      }
      
      
      /**
       * 授权
       *
       * @param principalCollection
       * @return
       */
      @Override
      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            // 获取认证传递过来的对象集
            ActiveUser active = (ActiveUser) principalCollection.getPrimaryPrincipal();
            // 获取权限
            List<String> permissions = active.getPermissions();
            System.out.println("权限啊" + permissions);
            // 获取角色
            List<String> roles = active.getRoles();
            // 获取用户
            User user = active.getUser();
            // 判断是否为超级管理员
            if (user.getType().equals(Constant.USER_TYPE_SUPER)) {
                  info.addStringPermission("*:*");
            } else {
                  // 不是超级管理员
                  if (null != roles && roles.size() > 0) {
                        info.addRoles(roles);
                  }
                  if (null != permissions && permissions.size() > 0) {
                        info.addStringPermissions(permissions);
                  }
            }
            return info;
      }
      
      
}